/**
 * 用户信息业务处理模块
 * @module router_handler/userinfo
 * @version 1.0.0
 * @author 技术架构组
 * @since 2024-01-01
 * @description 负责用户信息相关的核心业务逻辑实现，属于「业务逻辑层（Service Layer）」，
 *              承上启下：接收路由层（routes）的请求，调用数据访问层（db）执行数据库操作，
 *              处理业务规则后统一封装响应，返回给前端。
 * 
 * 核心依赖：
 * - ../db/index：数据库操作核心模块（基于mysql2/promise封装，支持参数化查询，防SQL注入）
 * 业务关联：
 * - 路由层：对应 ./router/userinfo.js 的 /my/userinfo 接口
 * - 数据层：操作 ev_users 表（用户基础信息表）
 * 
 * 安全约束：
 * 1. 仅处理已通过JWT认证的请求（req.auth.id 由前置JWT中间件解析并验证合法性）
 * 2. 严格过滤敏感字段（如 password、is_admin），禁止返回给前端
 * 3. 所有数据库操作使用参数化查询，杜绝SQL注入风险
 */

// 导入数据库操作模块（已封装连接池、错误处理基础逻辑）
const db = require('../db/index');
const bcrypt = require('bcrypt')

/**
 * 根据用户ID查询当前登录用户的基础信息
 * @function getUserInfo
 * @description 从JWT解析的用户ID（req.auth.id）出发，查询ev_users表中指定用户的非敏感信息，
 *              确保查询结果唯一（ID为主键），并按统一格式返回响应
 * 
 * @param {Object} req - Express请求对象
 * @param {Object} req.auth - JWT认证后挂载的用户身份信息（由express-jwt中间件注入）
 * @param {number} req.auth.id - 用户唯一标识（主键ID，已通过JWT签名验证，确保合法性）
 * @param {Object} res - Express响应对象
 * @param {Function} res.cc - 全局封装的统一响应方法（见app.js中间件，支持错误/成功响应）
 * 
 * @returns {void} 无返回值，通过res.cc直接发送HTTP响应
 * 
 * @response 成功响应格式（HTTP 200）
 * {
 *   "status": 0,
 *   "message": "查询用户信息成功",
 *   "data": {
 *     "id": 1001,          // 用户主键ID
 *     "username": "zhangsan", // 用户名（唯一）
 *     "nickname": "张三",   // 用户昵称
 *     "email": "zhangsan@example.com", // 用户邮箱
 *     "user_pic": "https://xxx.com/avatar.jpg" // 用户头像URL
 *   }
 * }
 * 
 * @response 失败响应格式（HTTP 200，业务状态码1）
 * - 数据库错误：{ "status": 1, "message": "数据库查询失败：[具体错误信息]" }
 * - 用户不存在：{ "status": 1, "message": "查询用户信息失败！" }
 */
exports.getUserInfo = (req, res) => {
  /**
   * SQL查询语句设计（企业级数据安全&性能考量）
   * 1. 字段筛选：仅查询前端需展示的非敏感字段（id/username/nickname/email/user_pic），
   *    严格排除敏感字段（如password密码、is_admin管理员标识），符合「最小权限原则」
   * 2. 参数化查询：使用 ? 占位符接收用户ID，由db模块自动处理参数转义，彻底防止SQL注入攻击
   * 3. 条件精准：通过主键id查询（ev_users.id为主键，索引优化），确保查询性能（O(1)级），
   *    同时保证结果唯一性（主键唯一约束，不会返回多条数据）
   * 
   * 扩展说明：若后续需新增返回字段（如用户手机号），需满足：
   * - 该字段非敏感（或已脱敏处理）
   * - 前端确有业务需求
   * - 需同步更新接口文档（如Swagger）
   */
  const sqlStr = 'select id, username, nickname, email, user_pic from ev_users where id = ?';

  /**
   * 执行数据库查询（企业级错误处理逻辑）
   * @param {string} sqlStr - 预编译SQL语句
   * @param {Array} [req.auth.id] - SQL参数列表（对应?占位符，此处为用户ID）
   * @param {Function} callback - 查询结果回调函数
   */
  db.query(sqlStr, req.auth.id, (err, results) => {
    // 1. 捕获数据库执行错误（如连接超时、SQL语法错误等）
    // 开发环境：返回具体错误信息（便于排查问题）；生产环境：建议返回通用提示（避免暴露数据库细节）
    if (err) {
      return res.cc(`数据库查询失败：${err.message}`);
    }

    // 2. 验证查询结果有效性（基于业务规则）
    // 由于id是主键（唯一约束），正常情况下results长度应为1；若为0，说明用户不存在（如ID被删除但Token未过期）
    if (results.length !== 1) {
      return res.cc('查询用户信息失败！');
    }

    // 3. 成功响应：返回查询结果（取results[0]，因主键唯一确保仅一条数据）
    // 响应格式严格遵循全局统一规范，包含status（业务状态码）、message（提示信息）、data（业务数据）
    res.cc({
      status: 0,
      message: '查询用户信息成功',
      data: results[0] // 直接取第一条结果（符合主键查询的唯一性预期）
    });
  });
};

exports.updatedUserInfo = (req,res) => {
  const sqlStr = 'update ev_users set ? where id = ?'

  db.query(sqlStr,[req.body,req.body.id],(err,results) => {
    if(err) return res.cc('服务器繁忙，请稍后再试')
    if(results.affectedRows !== 1) return res.cc('更新用户失败')
    
    res.cc('更新用户成功！',0)
  })
}

exports.updatedPassword = (req,res) => {
  const sql = 'select * from ev_users where id = ?'
  db.query(sql,req.auth.id,(err,results) => {
    if(err) return res.cc(err)
    if(results.length !== 1) return res.cc('用户不存在！')
    
    const compareResult = bcrypt.compareSync(req.body.oldPwd,results[0].password)
    if(!compareResult) return res.cc('原密码错误！')

    const sql = 'update ev_users set password = ? where id = ?'
    const newPwd = bcrypt.hashSync(req.body.newPwd,10)
    db.query(sql,[newPwd,req.auth.id],(err,results) => {
      if(err) return res.cc(err)
      if(results.affectedRows !== 1) return res.cc('更新密码失败！')

      res.cc("更新密码成功",0)
    })
  })
}

exports.updateAvater = (req,res) => {
  const sqlStr = 'update ev_users set user_pic = ? where id = ?'

  db.query(sqlStr,[req.body.avatar,req.auth.id],(err,results) => {
    if(err) return res.cc(err)
    if(results.affectedRows !== 1) return res.cc('更新头像失败')

    res.cc('更新用户头像成功',0)
  })
}